package com.itlong.cloud.utils.encrypt;

import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.VO.MessageVO;
import com.itlong.cloud.POJO.VO.SDKMessageVO;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.lang.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.*;
import java.util.*;

/**
 * <desc>
 * des加解密帮助类
 * </desc>
 *
 * @createDate 2017/09/19
 */
public class DesEncryptUtil {

    // 向量
    public final static String iv = "0123456789123456";
    // 密钥
    public final static String secretKey = "0123456789123456";

    //QRCODE 初始秘钥
    public static final String QRCODE_INIT_KEY = "AB8E45C5D8A9A898";


    /**
     * <desc>
     * 获取加密key
     * key[0]= INIT_KEY[0]^PROJ_NO[0]
     * key[1]= INIT_KEY[1]^PROJ_NO[1]
     * key[2]= INIT_KEY[2]^PROJ_NO[2]
     * key[3]= INIT_KEY[3]^PROJ_NO[3]
     * key[4]= INIT_KEY[4]^ (~PROJ_NO[0])
     * key[5]= INIT_KEY[5]^ (~PROJ_NO[1])
     * key[6]= INIT_KEY[6]^ (~PROJ_NO[2])
     * key[7]= INIT_KEY[7]^ (~PROJ_NO[3])
     * </desc>
     *
     * @param initKey
     * @param projectNo
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static byte[] getQrcodeKey(String initKey, String projectNo) {
        try {
            byte[] initKeyByte = hexStrToBytes(initKey);
            byte[] projectNoByte = hexStrToBytes(projectNo);
            for (int i = 0; i < projectNoByte.length; i++) {
                String ik = hexString2binaryString(bytesToHexStr(new byte[]{initKeyByte[i]}));
                String pro = hexString2binaryString(bytesToHexStr(new byte[]{projectNoByte[i]}));
                initKeyByte[i] = hexStrToBytes(binaryString2hexString(xor(ik, pro)).toUpperCase())[0];
            }
            for (int i = 0; i < projectNoByte.length; i++) {
                String ik = hexString2binaryString(bytesToHexStr(new byte[]{initKeyByte[i + 4]}));
                String pro = hexString2binaryString(bytesToHexStr(new byte[]{projectNoByte[i]}));
                //二进制取反
                pro = inverseBinary(pro);
                initKeyByte[i + 4] = hexStrToBytes(binaryString2hexString(xor(ik, pro)).toUpperCase())[0];
            }
            return initKeyByte;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 获取授权二维码Mac值
     * MAC算法:
     * 将字符串qrcode分为8字节为单位的数据块，不足补\x00,分别标号为D1,D2,D3,...,Dn
     * 设置初始向量E0="\x00\x00\x00\x00\x00\x00\x00\x00"
     * 将E0^D1 —---->E1(E0,D1异或的后结果经des加密得到E1)
     * 将E1^D2 ----->E2
     * 如此类推，知道得出En结束，En即是计算出来的MAC
     * </desc>
     *
     * @param value  采用二维码中 “生成日期（5Byte：年/月/日/时/分）+流水号（1Byte） +有效时间（1Byte：*10分钟）+有效次数（1Byte）”8Byte数据作为初始向量
     * @param key    项目秘钥
     * @param qrcode 二维码数据
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String ownerAndVisitorMacEncrypt(String value, String key, String qrcode) throws NoSuchProviderException {
        try {
            while (qrcode.length() % 16 != 0) {
                qrcode += "0";
            }
            List<byte[]> bytes = new ArrayList<>();
            for (int i = 0; i < qrcode.length() / 16; i++) {
                bytes.add(hexStrToBytes(qrcode.substring(i * 16, i * 16 + 16)));
            }
            byte[] vi = hexStrToBytes(value);
            byte[] bKey = hexStrToBytes(key);
            String ds = "";
            for (byte[] bt : bytes) {
                for (int i = 0; i < bt.length; i++) {
                    String ik = hexString2binaryString(bytesToHexStr(new byte[]{bt[i]}));
                    String pro = hexString2binaryString(bytesToHexStr(new byte[]{vi[i]}));
                    vi[i] = hexStrToBytes(binaryString2hexString(xor(ik, pro)).toUpperCase())[0];
                }
                // 创建一个DESKeySpec对象
                SecretKeySpec spec = new SecretKeySpec(bKey, "DES");
                // Cipher对象实际完成加密操作
                try {
                    Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
                    // 实例化cipher
                    cipher.init(Cipher.ENCRYPT_MODE, spec);
                    // 开始加密
                    vi = cipher.doFinal(vi);
                    ds = bytesToHexStr(vi);
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (NoSuchPaddingException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (IllegalBlockSizeException e) {
                    e.printStackTrace();
                } catch (BadPaddingException e) {
                    e.printStackTrace();
                }
            }
            return ds.toUpperCase().substring(0, 8);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 获取授权二维码Mac值
     * MAC算法:
     * 将字符串qrcode分为8字节为单位的数据块，不足补\x00,分别标号为D1,D2,D3,...,Dn
     * 设置初始向量E0="\x00\x00\x00\x00\x00\x00\x00\x00"
     * 将E0^D1 —---->E1(E0,D1异或的后结果经des加密得到E1)
     * 将E1^D2 ----->E2
     * 如此类推，知道得出En结束，En即是计算出来的MAC
     * </desc>
     *
     * @param value  采用二维码中 “生成日期（5Byte：年/月/日/时/分）+流水号（1Byte） +有效时间（1Byte：*10分钟）+有效次数（1Byte）”8Byte数据作为初始向量
     * @param key    项目秘钥
     * @param qrcode 二维码数据
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String newOwnerAndVisitorMacEncrypt(String value, String key, String qrcode) throws NoSuchProviderException {
        try {
            qrcode = stringToAscii(qrcode);
            System.out.println(qrcode);
            while (qrcode.length() % 16 != 0) {
                qrcode += "0";
            }
            List<byte[]> bytes = new ArrayList<>();
            for (int i = 0; i < qrcode.length() / 16; i++) {
                bytes.add(hexStrToBytes(qrcode.substring(i * 16, i * 16 + 16)));
            }
            byte[] vi = hexStrToBytes(value);
            byte[] bKey = hexStrToBytes(key);
            String ds = "";
            for (byte[] bt : bytes) {
                for (int i = 0; i < bt.length; i++) {
                    String ik = hexString2binaryString(bytesToHexStr(new byte[]{bt[i]}));
                    String pro = hexString2binaryString(bytesToHexStr(new byte[]{vi[i]}));
                    vi[i] = hexStrToBytes(binaryString2hexString(xor(ik, pro)).toUpperCase())[0];
                }
                // 创建一个DESKeySpec对象
                SecretKeySpec spec = new SecretKeySpec(bKey, "DES");
                // Cipher对象实际完成加密操作
                try {
                    Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
                    // 实例化cipher
                    cipher.init(Cipher.ENCRYPT_MODE, spec);
                    // 开始加密
                    vi = cipher.doFinal(vi);
                    ds = bytesToHexStr(vi);
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (NoSuchPaddingException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (IllegalBlockSizeException e) {
                    e.printStackTrace();
                } catch (BadPaddingException e) {
                    e.printStackTrace();
                }
            }
            return ds.toUpperCase().substring(0, 8);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 获取授权二维码Mac值
     * MAC算法:
     * 将字符串qrcode分为8字节为单位的数据块，不足补\x00,分别标号为D1,D2,D3,...,Dn
     * 设置初始向量E0="\x00\x00\x00\x00\x00\x00\x00\x00"
     * 将E0^D1 —---->E1(E0,D1异或的后结果经des加密得到E1)
     * 将E1^D2 ----->E2
     * 如此类推，知道得出En结束，En即是计算出来的MAC
     * </desc>
     *
     * @param value     取VALID_TIME（7）+0x00作为初始向量
     * @param initKey   初始秘钥
     * @param projectNo 项目编号
     * @param qrcode    二维码数据
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String qrcodeAuthMacEncrypt(String value, String initKey, String projectNo, String qrcode) throws NoSuchProviderException {
        try {
            while (qrcode.length() % 16 != 0) {
                qrcode += "0";
            }
            List<byte[]> bytes = new ArrayList<>();
            for (int i = 0; i < qrcode.length() / 16; i++) {
                bytes.add(hexStrToBytes(qrcode.substring(i * 16, i * 16 + 16)));
            }
            byte[] vi = hexStrToBytes(value);
            byte[] bKey = getQrcodeKey(initKey, projectNo);
            String ds = "";
            for (byte[] bt : bytes) {
                for (int i = 0; i < bt.length; i++) {
                    String ik = hexString2binaryString(bytesToHexStr(new byte[]{bt[i]}));
                    String pro = hexString2binaryString(bytesToHexStr(new byte[]{vi[i]}));
                    vi[i] = hexStrToBytes(binaryString2hexString(xor(ik, pro)).toUpperCase())[0];
                }
                // 创建一个DESKeySpec对象
                SecretKeySpec spec = new SecretKeySpec(bKey, "DES");
                // Cipher对象实际完成加密操作
                try {
                    Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
                    // 实例化cipher
                    cipher.init(Cipher.ENCRYPT_MODE, spec);
                    // 开始加密
                    vi = cipher.doFinal(vi);
                    ds = bytesToHexStr(vi);
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (NoSuchPaddingException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (IllegalBlockSizeException e) {
                    e.printStackTrace();
                } catch (BadPaddingException e) {
                    e.printStackTrace();
                }
            }
            return ds.toUpperCase().substring(0, 8);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 字符串转ascii码
     * </desc>
     *
     * @param value
     * @return
     * @author Jiaqi.X
     * @createDate 2019/10/16
     */
    public static String stringToAscii(String value) {
        StringBuilder sbu = new StringBuilder();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        String[] str = StringHandlerUtil.splitString(sbu.toString());
        StringBuilder result = new StringBuilder();
        for (String s : str) {
            result.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(Integer.valueOf(s)), "0").toUpperCase());
        }
        return result.toString();
    }

    /**
     * <desc>
     * 十六进制转二进制
     * </desc>
     *
     * @param hexString
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String hexString2binaryString(String hexString) {
        try {
            if (hexString == null || hexString.length() % 2 != 0)
                return null;
            String bString = "", tmp;
            for (int i = 0; i < hexString.length(); i++) {
                tmp = "0000"
                        + Integer.toBinaryString(Integer.parseInt(hexString
                        .substring(i, i + 1), 16));
                bString += tmp.substring(tmp.length() - 4);
            }
            return bString;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 获取加密后的projKey
     * </desc>
     *
     * @param initKey   初始秘钥
     * @param projectNo 项目编号
     * @param projKey   项目秘钥
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String ProjKeyEncrypt(String initKey, String projectNo, String projKey) throws Exception {
        try {
            byte[] dataBytes = StringHandlerUtil.hexStrToBytes(projKey);
            DESKeySpec dks = new DESKeySpec(getQrcodeKey(initKey, projectNo));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encryptedBytes = cipher.doFinal(dataBytes);
            return StringHandlerUtil.bytesToHexStr(encryptedBytes);
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     * <desc>
     * DES加密
     * </desc>
     *
     * @param datasource byte[]
     * @param password   String
     * @return byte[]
     * @author Jiaqi.X
     * @createDate 2017/09/15
     */
    public static byte[] Encrypt(byte[] datasource, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            //创建一个密匙工厂，然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            //Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            //用密匙初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            //现在，获取数据并加密
            //正式执行加密操作
            return cipher.doFinal(datasource);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * DES 解密
     *
     * @param src      byte[]
     * @param password String
     * @return byte[]
     * @throws Exception
     * @author Jiaqi.X
     * @createDate 2017/09/15
     */
    public static byte[] Decrypt(byte[] src, String password) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(password.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }


    /**
     * <desc>
     * SDK项目ID加密
     * <desc/>
     *
     * @param data 待加密数据  secretKey是密钥,iv是向量
     * @return
     * @author Biao.R
     * @createDate 2017/11/3
     */
    public static String projectIdEncrypt(String data, String secretKey, String iv) throws Exception {
        if (StringUtils.isEmpty(secretKey)) {
            secretKey = DesEncryptUtil.secretKey;
        }
        if (StringUtils.isEmpty(iv)) {
            iv = DesEncryptUtil.iv;
        }
        if (StringUtils.isEmpty(data)) {
            return null;
        }
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();

            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }

            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyspec = new SecretKeySpec(secretKey.getBytes(), "AES");
            System.out.println("IndexFra----" + StringHandlerUtil.bytesToHexStr(secretKey.getBytes()));
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return Base64.encode(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * <desc>
     * SDK项目ID解密
     * <desc/>
     *
     * @param data 待解密数据
     * @return
     * @author Biao.R
     * @createDate 2017/11/3
     */
    public static String projectIdDesEncrypt(String data) throws Exception {
        try {
            if (StringUtils.isEmpty(data)) {
                return null;
            }
            byte[] encrypted1 = Base64.decode(data);
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keyspec = new SecretKeySpec(secretKey.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString.trim().replaceAll(" +", "");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static <T> Object deviceParamAes(T model, String aesKey) throws Exception {
        Field[] field = model.getClass().getDeclaredFields(); // 获取实体类的所有属性，返回Field数组
        try {
            for (int j = 0; j < field.length; j++) { // 遍历所有属性
                String name = field[j].getName(); // 获取属性的名字
                name = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写，方便构造get，set方法
                String type = field[j].getGenericType().toString(); // 获取属性的类型
                if (type.equals("class java.lang.String")) { // 如果type是类类型，则前面包含"class "，后面跟类名
                    Method m = model.getClass().getMethod("get" + name);
                    String value = (String) m.invoke(model); // 调用getter方法获取属性值
                    if (value != null) {
                        m = model.getClass().getMethod("set" + name, String.class);
                        m.invoke(model, DesEncryptUtil.aesDecrypt(value, aesKey));
                    }
                } else {
                    throw new DataAccessException("【智能设备加密】智能设备响应结果加密失败");
                }
                // 如果有需要,可以仿照上面继续进行扩充,再增加对其它类型的判断
            }
            return model;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return model;
    }

    /**
     * <desc>
     * 根据待加密的键值对进行云对讲的设备数据通信加密
     * </desc>
     *
     * @param secretContent 密文串 BASE64(AES(content))+MD5
     * @param sKey
     * @param md5Salt
     * @return
     * @throws Exception
     */
    public static String deviceParamAes(String secretContent, String sKey, String md5Salt) throws Exception {
        try {
            return aesEncrypt(secretContent.toString(), sKey, md5Salt);
        } catch (Exception e) {
            return "";
        }
    }


    //DES算法填充方式
    public static final String ALGORITHM_DES = "DES/ECB/NoPadding";

    /**
     * <desc>
     * DES算法，加密.
     * </desc>
     *
     * @param data 待加密的HEX字符串
     * @param key  加密私钥，HEX字符串，长度不能够小于8位
     * @return 加密字符串
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    public static String encode(String key, String data) throws Exception {
        try {
            //key的长度不能够小于8位字节
            key = StringHandlerUtil.fillString(key, "0", 16);
            data = StringHandlerUtil.fillString(data, "0", 16);
            byte[] keyBytes = StringHandlerUtil.hexStrToBytes(key);
            byte[] dataBytes = StringHandlerUtil.hexStrToBytes(data);
            DESKeySpec dks = new DESKeySpec(keyBytes);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] encryptedBytes = cipher.doFinal(dataBytes);
            return StringHandlerUtil.bytesToHexStr(encryptedBytes);
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    /**
     * <desc>
     * 将两个二进制数做异或运算
     * </desc>
     *
     * @param anotherBinary
     * @param thisBinary
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    private static String xor(String anotherBinary, String thisBinary) {
        try {
            String result = "";
            //判断是否为8位二进制，否则左补零
            if (anotherBinary.length() != 8) {
                for (int i = anotherBinary.length(); i < 8; i++) {
                    anotherBinary = "0" + anotherBinary;
                }
            }
            if (thisBinary.length() != 8) {
                for (int i = thisBinary.length(); i < 8; i++) {
                    thisBinary = "0" + thisBinary;
                }
            }
            //异或运算
            for (int i = 0; i < anotherBinary.length(); i++) {
                //如果相同位置数相同，则补0，否则补1
                if (thisBinary.charAt(i) == anotherBinary.charAt(i))
                    result += "0";
                else {
                    result += "1";
                }
            }
            return result;
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     * <desc>
     * 二进制取反
     * </desc>
     *
     * @param binary
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String inverseBinary(String binary) {
        try {
            StringBuilder bi = new StringBuilder();
            for (int i = 0; i < binary.length(); i++) {
                String b = binary.substring(i, i + 1);
                if (b.equals("0")) {
                    bi.append("1");
                } else {
                    bi.append("0");
                }
            }
            return bi.toString();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 二进制转十六进制
     * </desc>
     *
     * @param bString
     * @return
     * @author Jiaqi.X
     * @createDate 2017/12/20
     */
    public static String binaryString2hexString(String bString) {
        try {
            if (bString == null || bString.equals("") || bString.length() % 8 != 0)
                return null;
            StringBuffer tmp = new StringBuffer();
            int iTmp = 0;
            for (int i = 0; i < bString.length(); i += 4) {
                iTmp = 0;
                for (int j = 0; j < 4; j++) {
                    iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);
                }
                tmp.append(Integer.toHexString(iTmp));
            }
            return tmp.toString();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * <desc>
     * 把16进制字符串转换成字节数组.
     * </desc>
     *
     * @param hex 待转换的Hex字符串
     * @return 转换得到的byte数组
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    public static byte[] hexStrToBytes(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    /**
     * <desc>
     * 将单个十六进制字符转换为字节
     * </desc>
     *
     * @param c 单个字符
     * @return 转换得到的byte
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    private static byte toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    /**
     * <desc>
     * 把字节数组转换成16进制字符串.
     * </desc>
     *
     * @param bArray 待转换的byte数组
     * @return 转换得到的Hex字符串
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    public static String bytesToHexStr(byte[] bArray) {
        if (bArray == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * <desc>
     * 自动后补齐字符串
     * </desc>
     *
     * @param str    字符串
     * @param supply 待填充的字符
     * @param length 要求填充后达到的字符串总长度
     * @return 填充后的字符串
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    public static String fillString(String str, String supply, int length) {
        StringBuffer sb = new StringBuffer(str);
        while (sb.length() < length) {
            sb.append(supply);
        }
        return sb.toString();
    }

    /**
     * <desc>
     * DES算法，解密.
     * </desc>
     *
     * @param data 待解密的HEX字符串
     * @param key  解密私钥，HEX字符串，长度不能够小于8位
     * @return 解密后的字符串
     * @throws Exception 异常
     * @author LewisLouis
     * @createDate 2017-11-10
     */
    public static String decode(String key, String data) throws Exception {
        //key的长度不能够小于8位字节
        key = StringHandlerUtil.fillString(key, "0", 16);
        byte[] keyBytes = StringHandlerUtil.hexStrToBytes(key);
        byte[] dataBytes = StringHandlerUtil.hexStrToBytes(data);
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        Key secretKey = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedBytes = cipher.doFinal(dataBytes);
        return StringHandlerUtil.bytesToHexStr(decryptedBytes);
    }

    /**
     * <desc>
     * 云端设备AES加密方案
     * </desc>
     *
     * @param sSrc
     * @param sKey
     * @param md5Salt
     * @return
     * @throws Exception
     */
    public static String aesEncrypt(String sSrc, String sKey, String md5Salt) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        StringBuilder stringBuilder = new StringBuilder();
        if (encrypted == null || encrypted.length <= 0) {
            return null;
        }
        for (int i = 0; i < encrypted.length; i++) {
            int v = encrypted[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        // System.out.println("hex码:"+stringBuilder.toString());

        String base64Str = new Base64().encode(encrypted);//此处使用BASE64做转码功能，同时能起到2次加密的作用。
        //  System.out.println("base64结果:"+base64Str);

        String md5Str = Md5EncryptUtil.md5(base64Str + md5Salt).toUpperCase();
        //    System.out.println("md5Str结果:"+md5Str);
        return base64Str + md5Str;
    }

    /**
     * <desc>
     * 云端设备AES加密方案
     * </desc>
     *
     * @param sSrc
     * @param sKey
     * @return
     * @throws Exception
     */
    public static String aesEncryptSDK(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        StringBuilder stringBuilder = new StringBuilder();
        if (encrypted == null || encrypted.length <= 0) {
            return null;
        }
        for (int i = 0; i < encrypted.length; i++) {
            int v = encrypted[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        String base64Str = new Base64().encode(encrypted);//此处使用BASE64做转码功能，同时能起到2次加密的作用。
        return base64Str;
    }

    /**
     * <desc>
     * 云端设备AES解密
     * </desc>
     *
     * @param sSrc
     * @param sKey
     * @return
     * @throws Exception
     */
    public static String aesDecrypt(String sSrc, String sKey) throws Exception {
        try {
            // 判断Key是否正确
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            if (sSrc.length() < 32) {
                System.out.print("密文串错误");
                return null;
            }
            byte[] raw = sKey.getBytes("utf-8");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original, "utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    /**
     * <desc>
     * APP传参AES解密
     * </desc>
     *
     * @param sSrc
     * @param sKey
     * @return
     * @throws Exception
     */
    public static String aesDecryptApp(String sSrc, String sKey) throws Exception {
        try {
            // 判断Key是否正确
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            if (sSrc.length() < 32) {
                System.out.print("密文串错误");
                return null;
            }
            byte[] raw = sKey.getBytes("utf-8");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/NOPadding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original, "utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    /**
     * <desc>
     * APP传参AES加密方案
     * </desc>
     *
     * @param sSrc
     * @param sKey
     * @return
     * @throws Exception
     */
    public static String aesEncryptSDKApp(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/NOPadding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        StringBuilder stringBuilder = new StringBuilder();
        if (encrypted == null || encrypted.length <= 0) {
            return null;
        }
        for (int i = 0; i < encrypted.length; i++) {
            int v = encrypted[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        String base64Str = new Base64().encode(encrypted);//此处使用BASE64做转码功能，同时能起到2次加密的作用。
        return base64Str;
    }

    /**
     * <desc>
     * userKey
     * </desc>
     *
     * @param datasource String userId
     * @param password   String projectKey
     * @return
     * @author Jiaqi.X
     * @createDate 2018/05/25
     */
    public static String getUserKey(String datasource, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(hexStrToBytes(password));
            //创建一个密匙工厂，然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            //Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            //用密匙初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            //现在，获取数据并加密
            //正式执行加密操作
            return bytesToHexStr(cipher.doFinal(hexStrToBytes(datasource))).substring(0, 16);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <desc>
     * 返回加密内容
     * </desc>
     *
     * @param appsecret 开发者用户密码
     * @return
     * @author Qiang.S
     * @createDate 2018/12/27
     */
    public static Map<String, Object> getEncryptResult(Object result, String appsecret) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            MessageVO messageVO = (MessageVO) result;
            String encryptResult;
            encryptResult = DesEncryptUtil.aesEncryptSDK(JsonUtil.toJSON(messageVO), appsecret);
            resultMap.put("encryptScript", encryptResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * <desc>
     * 返回加密内容sdkV2
     * </desc>
     *
     * @param appsecret 开发者用户密码
     * @return
     * @author Qiang.S
     * @createDate 2018/12/27
     */
    public static Map<String, Object> getEncryptResultSDKV2(Object result, String appsecret) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            SDKMessageVO messageVO = (SDKMessageVO) result;
            String encryptResult;
            encryptResult = DesEncryptUtil.aesEncryptSDK(JsonUtil.toJSON(messageVO), appsecret);
            resultMap.put("encryptScript", encryptResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * <desc>
     * 返回加密内容sdkV3
     * </desc>
     *
     * @param appsecret 开发者用户密码
     * @return
     * @author Qiang.S
     * @createDate 2018/12/27
     */
    public static Map<String, Object> getEncryptResultSDKV3(Object result, String appsecret) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String encryptResult;
            encryptResult = DesEncryptUtil.aesEncryptSDK(JSONObject.toJSONString(result), appsecret);
            resultMap.put("encryptScript", encryptResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * <desc>
     * 获取京东加密签名
     * </desc>
     *
     * @param json
     * @param url
     * @param appSecret
     * @return
     * @author Jiaqi.X
     * @createDate 2020/08/11
     */
    public static Map<String, Object> getJdSign(String json, String url, String appSecret) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        Map<String, Object> params = JsonUtil.toObject(json, HashMap.class);
        String id = params.get("id").toString();
        String protocol = JsonUtil.toJSON(params.get("protocol"));
        String client = JsonUtil.toJSON(params.get("client"));
        String param = JsonUtil.toJSON(params.get("params"));
        Long timestamp = (new Date()).getTime();
        String content = id + protocol + client + param + timestamp + url;
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        byte[] keyBytes = appSecret.getBytes("UTF-8");
        hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
        String sign = new String(new Base64().encode(hmacSha256.doFinal(content.getBytes("UTF-8"))));
        params.put("signature", sign);
        params.put("timestamp", timestamp);
        return params;
    }

    /**
     * <desc>
     * 校验京东签名
     * </desc>
     *
     * @param params
     * @return
     * @author Jiaqi.X
     * @createDate 2020/08/11
     */
    public static Boolean checkJdSign(Map<String, Object> params, String appSecret, String url) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        String id = params.get("id").toString();
        String protocol = JsonUtil.toJSON(params.get("protocol"));
        String client = JsonUtil.toJSON(params.get("client"));
        String param = JsonUtil.toJSON(params.get("params"));
        String timestamp = params.get("timestamp").toString();
        String content = id + protocol + client + param + timestamp + url;
        String signature = params.get("signature").toString();
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        byte[] keyBytes = appSecret.getBytes("UTF-8");
        hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
        String sign = new String(new Base64().encode(hmacSha256.doFinal(content.getBytes("UTF-8"))));
        if (sign.equals(signature)) {
            return true;
        } else {
            return false;
        }
    }

    //public static void main(String[] args)  throws Exception{
        /*try {
            String desProjectId = projectIdDesEncrypt("oSiWuhqyQK6sVLCAh/IBWg==");
            System.out.println(desProjectId);
        } catch (Exception e) {
            e.printStackTrace();
        }*/
    /*
     * 此处使用AES-128-ECB加密模式，key需要为16位。
     */
        /*String cKey = "1234567890123456";
        String md5Salt = "4645431343543213143";
        // 需要加密的字串
        String cSrc = "k1=v1&k2=v2&k3=v3";
        System.out.println(cSrc);
        // 加密
        String enString = DesEncryptUtil.aesEncrypt(cSrc, cKey,md5Salt);
        System.out.println("加密后的字串是：" + enString);
        // 解密
        String DeString = DesEncryptUtil.aesDecrypt(enString, cKey);
        System.out.println("解密后的字串是：" + DeString);*/
    //}

//    public static String convertStringToHex(String str){
//
//        char[] chars = str.toCharArray();
//
//        StringBuffer hex = new StringBuffer();
//        for(int i = 0; i < chars.length; i++){
//            hex.append(Integer.toHexString((int)chars[i]));
//        }
//
//        return hex.toString().toUpperCase();
//
//    }
//
//    public static String convertHexToString(String hex){
//
//        StringBuilder sb = new StringBuilder();
//        StringBuilder temp = new StringBuilder();
//
//        //49204c6f7665204a617661 split into two characters 49, 20, 4c...
//        for( int i=0; i<hex.length()-1; i+=2 ){
//
//            //grab the hex in pairs
//            String output = hex.substring(i, (i + 2));
//            //convert hex to decimal
//            int decimal = Integer.parseInt(output, 16);
//            //convert the decimal to character
//            sb.append((char)decimal);
//
//            temp.append(decimal);
//        }
//
//        return sb.toString();
//    }

}
